package pro.cherish.quartzlockdemo.da;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import pro.cherish.quartzlockdemo.entity.STimetask;
import pro.cherish.quartzlockdemo.job.HiJob;
import pro.cherish.quartzlockdemo.service.STimetaskService;
import pro.cherish.quartzlockdemo.util.SpringUtils;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component
public class InitQuartzJob implements ApplicationContextAware {
    private static ApplicationContext appCtx;
    public static SchedulerFactoryBean schedulerFactoryBean = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (this.appCtx == null) {
            this.appCtx = applicationContext;
        }
    }

    /**
     * @Description: 从数据库载入任务
     * @return: void
     * @Author: lys
     * @Date: 2020/8/8
     */
    public static void init() {
        STimetaskService sTimetaskService = SpringUtils.getBean(STimetaskService.class);
        schedulerFactoryBean = appCtx.getBean(SchedulerFactoryBean.class);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        try {
            log.info(scheduler.getSchedulerName());
        } catch (SchedulerException e1) {
            e1.printStackTrace();
        }
        // 这里从数据库中获取任务信息数据
        QueryWrapper<STimetask> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("job_status", 1);
        // 已发布的定时任务
        List<STimetask> list = sTimetaskService.list(queryWrapper);
        List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
        for (STimetask sTimetask : list) {
            ScheduleJob job = new ScheduleJob();
            job.setJobId(sTimetask.getId());
            job.setJobGroup(sTimetask.getGroupName()); // 任务组
            job.setJobName(sTimetask.getName());// 任务名称
            job.setJobStatus(sTimetask.getJobStatus()); // 任务发布状态
            job.setIsConcurrent(sTimetask.getIsConcurrent() == 1 ? "1" : "0"); // 运行状态
            job.setCronExpression(sTimetask.getCron());
            job.setBeanClass(sTimetask.getBeanName());// 一个以所给名字注册的bean的实例
            job.setMethodName(sTimetask.getMethodName());
            job.setJobData(sTimetask.getJobData()); // 参数
            jobList.add(job);
        }
        for (ScheduleJob job : jobList) {
            try {
                addJob(job);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 添加任务
     *
     * @throws SchedulerException
     */
    public static void addJob(ScheduleJob job) throws SchedulerException {
        if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {
            return;
        }
        schedulerFactoryBean = appCtx.getBean(SchedulerFactoryBean.class);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        log.info(scheduler + "...........................................add");
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        // 不存在，创建一个
        if (null == trigger) {
//            Class clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class
//                    : QuartzJobFactoryDisallowConcurrentExecution.class;
            Class clazz = HiJob.class;
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup())
                    .usingJobData("data", job.getJobData()).build();
            jobDetail.getJobDataMap().put("scheduleJob", job);
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            trigger = TriggerBuilder.newTrigger().withDescription(job.getJobId())
                    .withIdentity(job.getJobName(), job.getJobGroup())
                    .withSchedule(scheduleBuilder).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } else {
            // Trigger已存在，那么更新相应的定时设置
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).usingJobData("data", job.getJobData()).withSchedule(scheduleBuilder).build();
            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        }
        if ("0".equals(job.getIsConcurrent())) {
            JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
            scheduler.pauseJob(jobKey);
        }
    }

    public static void pauseJob(ScheduleJob job) throws SchedulerException {
        schedulerFactoryBean = appCtx.getBean(SchedulerFactoryBean.class);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        scheduler.pauseJob(jobKey);
    }

    public static void rescheduleJob(ScheduleJob job) throws SchedulerException {
        schedulerFactoryBean = appCtx.getBean(SchedulerFactoryBean.class);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
        Class<HiJob> clazz = HiJob.class;
        JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup())
                .usingJobData("data", job.getJobData()).build();
        jobDetail.getJobDataMap().put("scheduleJob", job);
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        Trigger trigger = TriggerBuilder.newTrigger().withDescription(job.getJobId())
                .withIdentity(job.getJobName(), job.getJobGroup())
                .withSchedule(scheduleBuilder).build();
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    public static void stopJob(ScheduleJob job) throws SchedulerException {
        schedulerFactoryBean = appCtx.getBean(SchedulerFactoryBean.class);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        scheduler.deleteJob(jobKey);
    }
}